package main

import (
	"bufio"
	"crypto/md5"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

// var files = make([][]byte, 0, 100)

//[]byte转md5
func ByteToMd5(fileByte []byte) string {
	has := md5.Sum(fileByte)
	//用新的切片存放
	has2 := has[:]
	md5Str := hex.EncodeToString(has2)
	return md5Str
}

//根据路径找到该路径下的所有文件，并返回
func GetFilesFromDir(path string) {
	//从目录path下找到所有的目录文件
	allDir, err := ioutil.ReadDir(path)
	//如果有错误发生就返回nil，不再进行查找
	if err != nil {
		fmt.Println(err)
	}
	//遍历获取到的每一个目录信息
	for _, dir := range allDir {
		if dir.IsDir() {
			//如果还是目录，就继续向下进行递归查找,并追加到返回切片中
			GetFilesFromDir(path + "/" + dir.Name())
			continue
		}
		//如果不是目录,就读取该文件并加入到files中
		fileName := path + "/" + dir.Name()
		// file, fileErr := ioutil.ReadFile(fileName)
		// if fileErr != nil {
		// 	fmt.Println(fileErr)
		// }
		md5str, MD5err := MD5sum(fileName)
		if MD5err != nil {
			fmt.Println(MD5err)
		}
		//打印文件名和MD5
		// fmt.Println(fileName + " 的MD5为 " + ByteToMd5(file))
		txt(fileName + " 的MD5为 " + md5str)
	}
}

func GetMd5strs(files [][]byte) []string {
	md5Strs := make([]string, len(files), len(files))
	for i := 0; i < len(files); i++ {
		md5Strs[i] = ByteToMd5(files[i])
	}
	return md5Strs
}

func main() {
	//将pathPtr指针作为命令行参数
	pathPtr := flag.String("path", "/", "is path")
	flag.Parse()
	GetFilesFromDir(*pathPtr)
}

func txt(newLine string) {
	f, err := os.OpenFile("md5.txt", os.O_APPEND|os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	_, err = fmt.Fprintln(f, newLine)
	if err != nil {
		fmt.Println(err)
		f.Close()
		return
	}
	err = f.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(newLine)
}

const bufferSize = 65536

// MD5sum returns MD5 checksum of filename
func MD5sum(filename string) (string, error) {
	if info, err := os.Stat(filename); err != nil {
		return "", err
	} else if info.IsDir() {
		return "", nil
	}

	file, err := os.Open(filename)
	if err != nil {
		return "", err
	}
	defer file.Close()

	hash := md5.New()
	for buf, reader := make([]byte, bufferSize), bufio.NewReader(file); ; {
		n, err := reader.Read(buf)
		if err != nil {
			if err == io.EOF {
				break
			}
			return "", err
		}

		hash.Write(buf[:n])
	}

	checksum := fmt.Sprintf("%x", hash.Sum(nil))
	return checksum, nil
}
